package org.dreamwork.assistant.tools.cli.gui;

import com.intellij.uiDesigner.core.GridConstraints;
import com.intellij.uiDesigner.core.GridLayoutManager;
import com.intellij.uiDesigner.core.Spacer;
import org.dreamwork.assistant.tools.cli.XMLReader;
import org.dreamwork.assistant.tools.persistence.gui.SwingTool;
import org.dreamwork.util.StringUtil;

import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.net.URI;
import java.net.URL;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Properties;

/**
 * Created by seth.yang on 2018/10/15
 */
public class MainFrame extends JFrame implements ActionListener {
    private JTextField txtName;
    private JTextField txtPom;
    private JButton btnPom;
    private JTextField txtMainClass;
    private JTextField txtJavaHome;
    private JButton btnJavaHome;
    private JTextField txtRepo;
    private JButton btnRepo;
    private JTextField txtOut;
    private JButton btnOut;
    private JList<String> listInclude;
    private JButton btnAddList;
    private JButton btnRemoveList;
    private JTextField txtConfigFile;
    private JButton btnConfigFile;
    private JCheckBox chkDebugPort;
    private JTextField txtDebugPort;
    private JCheckBox chkForceInclude;
    private JCheckBox chkRecursive;
    private JCheckBox chkCompile;
    private JCheckBox chkWindows;
    private JCheckBox chkLinux;
    private JButton btnCancel;
    private JButton btnDist;
    private JPanel root;
    private JLabel lblLink;

    private JFileChooser chooser = new JFileChooser ("..");
    private IncludeDirModel model = new IncludeDirModel ();
    private FileFilter POM = new FileFilter () {
        @Override
        public boolean accept (File f) {
            return f.isDirectory () || f.getName ().equals ("pom.xml");
        }

        @Override
        public String getDescription () {
            return "Maven Project File";
        }
    };
    private FileFilter DIR = new FileFilter () {
        @Override
        public boolean accept (File f) {
            return f.isDirectory ();
        }

        @Override
        public String getDescription () {
            return "Directory";
        }
    };
    private FileFilter ALL = new FileFilter () {
        @Override
        public boolean accept (File f) {
            return true;
        }

        @Override
        public String getDescription () {
            return "All Files";
        }
    };
    private Properties cache = new Properties ();

    private static final String PREFIX = "org.dreamwork.assistant.distributor";

    {
// GUI initializer generated by IntelliJ IDEA GUI Designer
// >>> IMPORTANT!! <<<
// DO NOT EDIT OR ADD ANY CODE HERE!
        $$$setupUI$$$ ();
    }

    /**
     * Method generated by IntelliJ IDEA GUI Designer
     * >>> IMPORTANT!! <<<
     * DO NOT edit this method OR call it in your code!
     *
     * @noinspection ALL
     */
    private void $$$setupUI$$$ () {
        root = new JPanel ();
        root.setLayout (new GridLayoutManager (13, 3, new Insets (10, 10, 10, 10), -1, -1));
        final Spacer spacer1 = new Spacer ();
        root.add (spacer1, new GridConstraints (0, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
        txtName = new JTextField ();
        txtName.setText ("");
        root.add (txtName, new GridConstraints (1, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension (150, -1), null, 0, false));
        final JLabel label1 = new JLabel ();
        label1.setText ("Name");
        label1.setDisplayedMnemonic ('N');
        label1.setDisplayedMnemonicIndex (0);
        root.add (label1, new GridConstraints (1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JLabel label2 = new JLabel ();
        label2.setText ("POM File");
        label2.setDisplayedMnemonic ('F');
        label2.setDisplayedMnemonicIndex (4);
        root.add (label2, new GridConstraints (2, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        txtPom = new JTextField ();
        root.add (txtPom, new GridConstraints (2, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension (150, -1), null, 0, false));
        btnPom = new JButton ();
        btnPom.setText ("...");
        root.add (btnPom, new GridConstraints (2, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JLabel label3 = new JLabel ();
        label3.setText ("Main Class");
        label3.setDisplayedMnemonic ('C');
        label3.setDisplayedMnemonicIndex (5);
        root.add (label3, new GridConstraints (3, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        txtMainClass = new JTextField ();
        root.add (txtMainClass, new GridConstraints (3, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension (150, -1), null, 0, false));
        final JLabel label4 = new JLabel ();
        label4.setText ("Java Home");
        label4.setDisplayedMnemonic ('J');
        label4.setDisplayedMnemonicIndex (0);
        root.add (label4, new GridConstraints (4, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        txtJavaHome = new JTextField ();
        root.add (txtJavaHome, new GridConstraints (4, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension (150, -1), null, 0, false));
        btnJavaHome = new JButton ();
        btnJavaHome.setText ("...");
        root.add (btnJavaHome, new GridConstraints (4, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JLabel label5 = new JLabel ();
        label5.setText ("Maven Rrpo");
        label5.setDisplayedMnemonic ('R');
        label5.setDisplayedMnemonicIndex (6);
        root.add (label5, new GridConstraints (5, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        txtRepo = new JTextField ();
        root.add (txtRepo, new GridConstraints (5, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension (150, -1), null, 0, false));
        btnRepo = new JButton ();
        btnRepo.setText ("...");
        root.add (btnRepo, new GridConstraints (5, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JLabel label6 = new JLabel ();
        label6.setText ("Out dir");
        label6.setDisplayedMnemonic ('O');
        label6.setDisplayedMnemonicIndex (0);
        root.add (label6, new GridConstraints (6, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        txtOut = new JTextField ();
        txtOut.setText ("../out");
        root.add (txtOut, new GridConstraints (6, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension (150, -1), null, 0, false));
        btnOut = new JButton ();
        btnOut.setText ("...");
        root.add (btnOut, new GridConstraints (6, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JLabel label7 = new JLabel ();
        label7.setText ("Include Dir");
        label7.setDisplayedMnemonic ('I');
        label7.setDisplayedMnemonicIndex (0);
        root.add (label7, new GridConstraints (7, 0, 1, 1, GridConstraints.ANCHOR_NORTHWEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JScrollPane scrollPane1 = new JScrollPane ();
        root.add (scrollPane1, new GridConstraints (7, 1, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
        listInclude = new JList ();
        scrollPane1.setViewportView (listInclude);
        final JPanel panel1 = new JPanel ();
        panel1.setLayout (new GridLayoutManager (3, 1, new Insets (0, 0, 0, 0), -1, -1));
        root.add (panel1, new GridConstraints (7, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        btnAddList = new JButton ();
        btnAddList.setText ("+");
        panel1.add (btnAddList, new GridConstraints (0, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final Spacer spacer2 = new Spacer ();
        panel1.add (spacer2, new GridConstraints (2, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
        btnRemoveList = new JButton ();
        btnRemoveList.setEnabled (true);
        btnRemoveList.setText ("-");
        panel1.add (btnRemoveList, new GridConstraints (1, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JLabel label8 = new JLabel ();
        label8.setText ("Config File");
        root.add (label8, new GridConstraints (9, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        txtConfigFile = new JTextField ();
        root.add (txtConfigFile, new GridConstraints (9, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension (150, -1), null, 0, false));
        btnConfigFile = new JButton ();
        btnConfigFile.setText ("...");
        root.add (btnConfigFile, new GridConstraints (9, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        chkDebugPort = new JCheckBox ();
        chkDebugPort.setText ("Debug Port");
        root.add (chkDebugPort, new GridConstraints (10, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        txtDebugPort = new JTextField ();
        txtDebugPort.setEnabled (false);
        txtDebugPort.setText ("5005");
        root.add (txtDebugPort, new GridConstraints (10, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, GridConstraints.SIZEPOLICY_FIXED, null, new Dimension (150, -1), null, 0, false));
        final JPanel panel2 = new JPanel ();
        panel2.setLayout (new GridLayoutManager (3, 3, new Insets (0, 0, 0, 0), -1, -1));
        root.add (panel2, new GridConstraints (11, 0, 1, 2, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        final Spacer spacer3 = new Spacer ();
        panel2.add (spacer3, new GridConstraints (2, 0, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_VERTICAL, 1, GridConstraints.SIZEPOLICY_WANT_GROW, null, null, null, 0, false));
        chkForceInclude = new JCheckBox ();
        chkForceInclude.setText ("Force Include");
        panel2.add (chkForceInclude, new GridConstraints (0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        chkWindows = new JCheckBox ();
        chkWindows.setText ("Windows script");
        panel2.add (chkWindows, new GridConstraints (1, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        chkLinux = new JCheckBox ();
        chkLinux.setText ("Linux Script");
        panel2.add (chkLinux, new GridConstraints (1, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        chkCompile = new JCheckBox ();
        chkCompile.setText ("Compile Dep");
        panel2.add (chkCompile, new GridConstraints (0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final Spacer spacer4 = new Spacer ();
        panel2.add (spacer4, new GridConstraints (0, 2, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
        final JPanel panel3 = new JPanel ();
        panel3.setLayout (new GridLayoutManager (1, 6, new Insets (0, 0, 0, 0), -1, -1));
        root.add (panel3, new GridConstraints (12, 0, 1, 3, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_BOTH, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, null, null, null, 0, false));
        btnCancel = new JButton ();
        btnCancel.setText ("Cancel");
        panel3.add (btnCancel, new GridConstraints (0, 5, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        btnDist = new JButton ();
        btnDist.setEnabled (false);
        btnDist.setText ("Distribute");
        panel3.add (btnDist, new GridConstraints (0, 4, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        lblLink = new JLabel ();
        lblLink.setText ("https://gitee.com/seth_yang/dreamwork/tree/master/modules/assistant");
        panel3.add (lblLink, new GridConstraints (0, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final Spacer spacer5 = new Spacer ();
        panel3.add (spacer5, new GridConstraints (0, 3, 1, 1, GridConstraints.ANCHOR_CENTER, GridConstraints.FILL_HORIZONTAL, GridConstraints.SIZEPOLICY_WANT_GROW, 1, null, null, null, 0, false));
        final JLabel label9 = new JLabel ();
        label9.setText ("visit");
        panel3.add (label9, new GridConstraints (0, 0, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        final JLabel label10 = new JLabel ();
        label10.setText ("for source code");
        panel3.add (label10, new GridConstraints (0, 2, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_FIXED, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
        chkRecursive = new JCheckBox ();
        chkRecursive.setText ("Recursive");
        root.add (chkRecursive, new GridConstraints (8, 1, 1, 1, GridConstraints.ANCHOR_WEST, GridConstraints.FILL_NONE, GridConstraints.SIZEPOLICY_CAN_SHRINK | GridConstraints.SIZEPOLICY_CAN_GROW, GridConstraints.SIZEPOLICY_FIXED, null, null, null, 0, false));
    }

    /**
     * @noinspection ALL
     */
    public JComponent $$$getRootComponent$$$ () {
        return root;
    }

    private static final class IncludeDirModel extends DefaultListModel<String> {
        private java.util.List<String> data = new ArrayList<> ();

        @Override
        public int getSize () {
            return data.size ();
        }

        @Override
        public String getElementAt (int index) {
            return data.get (index);
        }

        @Override
        public int size () {
            return data.size ();
        }

        @Override
        public boolean isEmpty () {
            return data.isEmpty ();
        }

        @Override
        public String elementAt (int index) {
            return data.get (index);
        }

        @Override
        public void addElement (String element) {
            data.add (element);
        }

        @Override
        public String get (int index) {
            return data.get (index);
        }

        void fireContentsChanged () {
            super.fireContentsChanged (data, 0, size ());
        }
    }

    public static void main (String[] args) throws Exception {
        UIManager.setLookAndFeel (UIManager.getSystemLookAndFeelClassName ());
        new MainFrame ();
    }

    private MainFrame () {
        super ("Java Distributor");
        setSize (800, 500);
        setResizable (false);
        SwingTool.center (this);
        setDefaultCloseOperation (WindowConstants.EXIT_ON_CLOSE);

        guiSetup ();

        setVisible (true);
        SwingTool.addConfirmExit (this);
    }

    private void guiSetup () {
        setContentPane (root);
        URL url = getClass ().getClassLoader ().getResource ("delivery.png");
        if (url != null) {
            ImageIcon icon = new ImageIcon ();
            setIconImage (icon.getImage ());
        }

        btnAddList.addActionListener (this);
        btnRemoveList.addActionListener (this);
        btnCancel.addActionListener (this);
        btnConfigFile.addActionListener (this);
        btnDist.addActionListener (this);
        btnJavaHome.addActionListener (this);
        btnOut.addActionListener (this);
        btnPom.addActionListener (this);
        btnRepo.addActionListener (this);

        chkCompile.addActionListener (this);
        chkDebugPort.addActionListener (this);
        chkForceInclude.addActionListener (this);
        chkLinux.addActionListener (this);
        chkWindows.addActionListener (this);
        chkRecursive.addActionListener (this);

        new Thread (new Runnable () {
            @Override
            public void run () {
                try {
                    restoreCache ();
                } catch (IOException e) {
                    e.printStackTrace ();
                }
                SwingUtilities.invokeLater (new Runnable () {
                    @Override
                    public void run () {
                        setTextFieldActionListener ();
                    }
                });
            }
        }).start ();
        listInclude.setModel (model);

        final Color color = lblLink.getForeground ();
        final String link = "https://gitee.com/seth_yang/dreamwork/tree/master/modules/assistant";
        lblLink.addMouseListener (new MouseAdapter () {
            @Override
            public void mouseClicked (MouseEvent e) {
                try {
                    Desktop.getDesktop ().browse (URI.create (link));
                } catch (IOException e1) {
                    e1.printStackTrace ();
                }
            }

            @Override
            public void mouseEntered (MouseEvent e) {
                lblLink.setText ("<html><u>" + link + "</u></html>");
                lblLink.setForeground (Color.BLUE);
                lblLink.setCursor (Cursor.getPredefinedCursor (Cursor.HAND_CURSOR));
            }

            @Override
            public void mouseExited (MouseEvent e) {
                lblLink.setText (link);
                lblLink.setForeground (color);
                lblLink.setCursor (Cursor.getDefaultCursor ());
            }
        });
    }

    private void setTextFieldActionListener () {
        txtDebugPort.addKeyListener (adapter);
        txtJavaHome.addKeyListener (adapter);
        txtRepo.addKeyListener (adapter);
        txtConfigFile.addKeyListener (adapter);
        txtMainClass.addKeyListener (adapter);
        txtName.addKeyListener (adapter);
        txtPom.addKeyListener (adapter);
        txtOut.addKeyListener (adapter);
    }

    private KeyAdapter adapter = new KeyAdapter () {
        @Override
        public void keyReleased (KeyEvent e) {
            checkButtonStatus ();
        }
    };

    private void restoreCache () throws IOException {
        File file = new File ("../conf/.cache");
        if (file.exists ()) {
            try (FileInputStream fis = new FileInputStream (file)) {
                cache.load (fis);
            }

            if (cache.containsKey (PREFIX + ".repo")) {
                txtRepo.setText (cache.getProperty (PREFIX + ".repo"));
            }
            if (cache.containsKey (PREFIX + ".java_home")) {
                txtJavaHome.setText (cache.getProperty (PREFIX + ".java_home"));
            }
        }
    }

    private void saveCache () throws IOException {
        File dir = new File ("../conf");
        if (!dir.exists () && !dir.mkdirs ()) {
            throw new IOException ("Can't create dir: " + dir.getCanonicalPath ());
        }
        File file = new File (dir, ".cache");
        try (OutputStream out = new FileOutputStream (file)) {
            cache.store (out, null);
        }
    }

    /**
     * Invoked when an action occurs.
     *
     * @param e the event trigger
     */
    @Override
    public void actionPerformed (ActionEvent e) {
        try {
            Object sender = e.getSource ();
            if (sender == btnCancel) {
                SwingTool.confirmExit (this);
            } else if (sender == btnDist) {
                distribute ();
            } else if (sender == btnAddList) {
                selectFile (listInclude, JFileChooser.DIRECTORIES_ONLY);
            } else if (sender == btnRemoveList) {
                int index = listInclude.getSelectedIndex ();
                model.removeElementAt (index);
                model.fireContentsChanged ();
                btnRemoveList.setEnabled (listInclude.getSelectedIndex () != -1);
            } else if (sender == btnConfigFile) {
                selectFile (txtConfigFile, JFileChooser.FILES_AND_DIRECTORIES, ALL);
                calcConfig ();
            } else if (sender == btnJavaHome) {
                selectFile (txtJavaHome, JFileChooser.DIRECTORIES_ONLY);
            } else if (sender == btnOut) {
                selectFile (txtOut, JFileChooser.DIRECTORIES_ONLY);
            } else if (sender == btnPom) {
                selectFile (txtPom, JFileChooser.FILES_AND_DIRECTORIES, POM);
                fillDefaultData ();
                calcConfig ();
            } else if (sender == btnRepo) {
                selectFile (txtRepo, JFileChooser.DIRECTORIES_ONLY);
            } else if (sender == chkDebugPort) {
                txtDebugPort.setEnabled (true);
            } else if (sender == listInclude) {
                if (listInclude.getSelectedIndex () != -1) {
                    btnRemoveList.setEnabled (true);
                } else {
                    btnRemoveList.setEnabled (false);
                }
            }
        } catch (Exception ex) {
            ex.printStackTrace ();
        }

        checkButtonStatus ();
    }

    private void calcConfig () {
        if (!StringUtil.isEmpty (txtConfigFile.getText ())) {
            String name = txtConfigFile.getText ().trim ();
            if (!StringUtil.isEmpty (txtPom.getText ())) {
                String pom = txtPom.getText ().trim ();
                Path p1 = Paths.get (name);
                Path p2 = Paths.get (pom);
                p2 = p2.getParent ();
                Path p3 = p2.relativize (p1);
                txtConfigFile.setText (p3.toString ());
            }
        }
    }

    private void selectFile (Object target, int type) throws IOException {
        selectFile (target, type, null);
    }

    private void selectFile (Object target, int type, FileFilter filter) throws IOException {
        chooser.setSelectedFile (null);
        chooser.setFileSelectionMode (type);
        if (filter != null)
            chooser.setFileFilter (filter);
        else {
            chooser.removeChoosableFileFilter (POM);
            chooser.setFileFilter (DIR);
        }
        int code = chooser.showOpenDialog (this);
        if (code == JFileChooser.APPROVE_OPTION) {
            File file = chooser.getSelectedFile ();
            if (file != null) {
                if (target instanceof JTextField) {
                    ((JTextField) target).setText (file.getCanonicalPath ());
                } else {
                    model.addElement (file.getCanonicalPath ());
                    model.fireContentsChanged ();
                }
            }
        }
    }

    private void fillDefaultData () {
        String pom = txtPom.getText ();
        if (!StringUtil.isEmpty (pom)) {
            final String p = pom.trim ();
            new Thread (new Runnable () {
                @Override
                public void run () {
                    try (FileInputStream fis = new FileInputStream (p)) {
                        XMLReader reader = new XMLReader (fis);
                        String artifactId = (String) reader.getValue ("artifactId");
                        if (StringUtil.isEmpty (artifactId)) {
                            artifactId = (String) reader.getValue ("parent/artifactId");
                        }

                        if (!StringUtil.isEmpty (artifactId)) {
                            if (StringUtil.isEmpty (txtName.getText ())) {
                                txtName.setText (artifactId);
                            }

                            String out = txtOut.getText ();
                            if (StringUtil.isEmpty (out) || "../out".equals (out.trim ())) {
                                txtOut.setText ("../out/" + artifactId);
                            }
                        }
                    } catch (Exception ex) {
                        ex.printStackTrace ();
                    }
                }
            }).start ();
        }
    }

    private void distribute () {
        java.util.List<String> args = new ArrayList<> ();
        if (StringUtil.isEmpty (txtName.getText ())) {
            showError ("Please input project name");
            return;
        }
        args.add ("-n");
        args.add (txtName.getText ().trim ());

        if (StringUtil.isEmpty (txtPom.getText ())) {
            showError ("Project file is missing");
            return;
        }
        args.add ("-p");
        args.add (txtPom.getText ().trim ());

        if (StringUtil.isEmpty (txtMainClass.getText ())) {
            showError ("Main class is missing");
            return;
        }
        args.add ("-m");
        args.add (txtMainClass.getText ().trim ());

        if (StringUtil.isEmpty (txtRepo.getText ())) {
            showError ("Maven repo is missing");
            return;
        }
        args.add ("-r");
        args.add (txtRepo.getText ().trim ());
        cache.setProperty (PREFIX + ".repo", txtRepo.getText ().trim ());

        if (chkDebugPort.isSelected ()) {
            if (StringUtil.isEmpty (txtDebugPort.getText ())) {
                showError ("debug port is missing");
                return;
            }

            try {
                int port = Integer.parseInt (txtDebugPort.getText ().trim ());
                args.add ("--debug-port=" + port);
                args.add ("--gen-debug-script");
            } catch (Exception ex) {
                showError ("Invalid debug port: " + txtDebugPort.getText ());
            }
        }

        if (!StringUtil.isEmpty (txtJavaHome.getText ())) {
            args.add ("-j");
            args.add (txtJavaHome.getText ().trim ());
            cache.setProperty (PREFIX + ".java_home", txtJavaHome.getText ().trim ());
        }

        args.add ("-o");
        args.add (txtOut.getText ().trim ());

        if (!StringUtil.isEmpty (txtConfigFile.getText ())) {
            args.add ("-C");
            args.add (txtConfigFile.getText ());
        }

        if (chkForceInclude.isSelected ()) {
            args.add ("-f");
        }
        if (chkRecursive.isSelected ()) {
            args.add ("-r");
        }
        if (chkCompile.isSelected ()) {
            args.add ("-c");
        }
        if (chkWindows.isSelected ()) {
            args.add ("--with-win-script");
        }
        if (chkLinux.isEnabled ()) {
            args.add ("--with-linux-script");
        }
        if (!model.isEmpty ()) {
            StringBuilder builder = new StringBuilder ();
            for (String e : model.data) {
                if (builder.length () > 0) {
                    builder.append (":");
                }
                builder.append (e);
            }
            args.add ("-i");
            args.add (builder.toString ());
        }

        System.out.println (args);
        String[] p = new String[args.size ()];
        p = args.toArray (p);
        new Thread (new Runnable () {
            @Override
            public void run () {
                try {
                    saveCache ();
                } catch (IOException e) {
                    e.printStackTrace ();
                }
            }
        }).start ();
        ExecuteDialog dialog = new ExecuteDialog (p);
        SwingTool.center (dialog, this);
        dialog.setVisible (true);
    }

    private void checkButtonStatus () {
        btnDist.setEnabled (
                !StringUtil.isEmpty (txtName.getText ()) &&
                        !StringUtil.isEmpty (txtPom.getText ()) &&
                        !StringUtil.isEmpty (txtMainClass.getText ()) &&
                        !StringUtil.isEmpty (txtRepo.getText ())
        );
    }

    private void showError (String message) {
        JOptionPane.showMessageDialog (this, message, "Error", JOptionPane.ERROR_MESSAGE);
    }

}
